use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
use x86_64::{
    PhysAddr, VirtAddr,
    structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB},
};

/// 初始化一个新的OffsetPageTable。
///
/// 这个函数是不安全的，因为调用者必须保证完整的物理内存在
/// 传递的`physical_memory_offset`处被映射到虚拟内存。另
/// 外，这个函数必须只被调用一次，以避免别名"&mut "引用（这是未定义的行为）。
pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
    unsafe {
        let level_4_table = active_level_4_table(physical_memory_offset);
        OffsetPageTable::new(level_4_table, physical_memory_offset)
    }
}

/// 返回一个对活动的4级表的可变引用。
///
/// 这个函数是不安全的，因为调用者必须保证完整的物理内存在传递的 
/// `physical_memory_offset`处被映射到虚拟内存。另外，这个函数
/// 必须只被调用一次，以避免别名"&mut "引用（这是未定义的行为）。
unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
    use x86_64::registers::control::Cr3;

    let (level_4_table_frame, _) = Cr3::read();

    let phys = level_4_table_frame.start_address();
    let virt = physical_memory_offset + phys.as_u64();///将物理地址转化成了虚拟地址，这样就可以访问到物理地址
    let page_table_ptr: *mut PageTable = virt.as_mut_ptr();

    unsafe { &mut *page_table_ptr }
}

/// A FrameAllocator that always returns `None`.
pub struct EmptyFrameAllocator;

unsafe impl FrameAllocator<Size4KiB> for EmptyFrameAllocator {
    fn allocate_frame(&mut self) -> Option<PhysFrame> {
        None
    }
}

/// 一个FrameAllocator，从bootloader的内存地图中返回可用的 frames。
pub struct BootInfoFrameAllocator {
    memory_map: &'static MemoryMap,
    next: usize,
}

impl BootInfoFrameAllocator {
    /// 从传递的内存 map 中创建一个FrameAllocator。
    ///
    /// 这个函数是不安全的，因为调用者必须保证传递的内存 map 是有效的。
    /// 主要的要求是，所有在其中被标记为 "可用 "的帧都是真正未使用的。
    pub unsafe fn init(memory_map: &'static MemoryMap) -> Self {
        BootInfoFrameAllocator {
            memory_map,
            next: 0,
        }
    }

    /// 返回内存映射中所有可用帧的迭代器。
    /// 该函数的主要目的是从 MemoryMap 中提取所有标记为 "可用" 的内存区域，
    /// 并将这些区域转换为物理帧（PhysFrame）的迭代器。
    fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
        // 调用 self.memory_map.iter() 获取内存映射中的所有区域。
        // memory_map 是一个引用，包含多个内存区域的信息。
        let regions = self.memory_map.iter();
        // 使用 filter 方法筛选出类型为 MemoryRegionType::Usable 的区域。
        // 这些区域是操作系统可以使用的内存部分。
        let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable);
        // 对每个可用区域调用 map 方法，
        // 将其转换为一个地址范围（start_addr 到 end_addr）
        let addr_ranges = usable_regions.map(|r| r.range.start_addr()..r.range.end_addr());
        // 使用 flat_map 将每个地址范围分解为以 4KB（4096 字节）为步长的帧起始地址
        let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
        // 使用 map 方法将每个帧起始地址转换为 PhysFrame 类型。
        frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)))
    }
}

unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
    fn allocate_frame(&mut self) -> Option<PhysFrame> {
        // 使用 nth(self.next) 方法跳过前 self.next 个帧，并返回第 self.next 个帧。
        // nth(n) 是迭代器方法，会跳过前 n 个元素并返回第 n 个元素。
        let frame = self.usable_frames().nth(self.next);
        self.next += 1;
        frame
    }
}
